//
//  EZSocket+Sync.swift
//
//  Created by ellzu gu on 2021/6/29.
//

import Foundation

/// ITSocket异步调用方法(线程安全)
/// 异步接口不做与同步接口交叉调用测试，如果使用异步接口，请全部异步
extension EZSocket {
    /// 准备Socket
    /// - Parameters:
    ///   - host: 目标域名或者IP
    ///   - hostPort: 目标端口
    ///   - interface: 本机网卡或IP 可以为空
    ///   - completion: 结束回调
    /// - Returns: Void
    public func asyncPrepare(host : String, hostPort : UInt16, local : String? = nil, localPort: UInt16 = 0, completion: (( EZError?)->Void)? ) -> Void {
        self.socketQueue.async {
            let error : EZError? = self.prepare(host: host, hostPort: hostPort, local: local, localPort: localPort);
            self.delegateQueue.async {
                completion?(error);
            }
        }
    }
    
//    public func asyncListen(local: String? = nil, port: UInt16, completion: ((EZError?)->Void)? ) -> Void {
//        self.socketQueue.async {
//            let error = self.listen(local: local, port: port)
//            self.delegateQueue.async {
//                completion?(error)
//            }
//        }
//    }
    
    /// 绑定到指定地址
    /// - Parameters:
    ///   - local: 本机IP或网卡名字 - 默认nil，nil就是任意地址
    ///   - port: 端口
    ///   - completion: 完成回调
    /// - Returns: Void
    public func asyncBind(local: String? = nil, port: UInt16, completion: ((EZError?)->Void)? ) -> Void {
        self.socketQueue.async {
            let error = self.prepare(host: nil, hostPort: 0, local: local, localPort: port)
            self.delegateQueue.async {
                completion?(error)
            }
        }
    }
    
    /// 链接目标地址
    /// - Parameters:
    ///   - host: 主机
    ///   - hostPort: 端口
    ///   - interface: 本机网卡
    ///   - completion: 链接结果
    /// - Returns: Void
    public func asyncConnect(host : String,
                        hostPort : UInt16,
                        local : String? = nil,
                        localPort: UInt16 = 0,
                        prepareHandler: /*@escaping*/((EZError?)->Void)? = nil,
                        completion: /*@escaping*/ ((EZError?)->Void)? = nil ) -> Void {
        self.socketQueue.async {
            let error : EZError? = self.prepare(host: host, hostPort: hostPort, local: local, localPort: localPort)
            self.delegateQueue.async {
                prepareHandler?(error)
            }
            self.connect(completion: completion)
        }
    }
    
    /// 发送数据
    /// - Parameters:
    ///   - data: 数据包
    ///   - timeout: 超时
    ///   - completion: 完成回调
    /// - Returns: Void
    public func asyncSend(data : Data, position: Int = 0, timeout : TimeInterval, completion : @escaping (EZError?)->Void) -> Void {
        self.socketQueue.async {
            let packet : Packet = Packet.init(data: data, timeout: timeout, completion: completion);
            packet.position = position;
            self.sendingPackets.append(packet);
            self.flushPacket();
        }
    }
    
    /// 发送数据到指定目标
    /// - Parameters:
    ///   - address: 目标地址
    ///   - data: 数据
    ///   - timeout: 超时
    ///   - completion: 完成回调
    /// - Returns: Void
    public func asyncSendto(address: sockaddr_storage, data : Data, position: Int = 0, timeout : TimeInterval, completion : @escaping (EZError?)->Void) -> Void {
        self.socketQueue.async {
            let packet : Packet = Packet.init(data: data, timeout: timeout, completion: completion);
            packet.position = position
            packet.targetAddress = address
            self.sendingPackets.append(packet);
            self.flushPacket();
        }
    }
    
    /// 接收数据
    /// - Parameters:
    ///   - timeout: 超时时间   0:循环接收, -1:接收单次 无超时设置, 大于0: 表示单次接收 数值是超时时间
    ///   - completion: 结果回调
    public func asyncReceive(timeout: TimeInterval, completion : @escaping (_ data: Data?, _ fromAddress: sockaddr_storage?, _ error: EZError?)->Void) {
        self.socketQueue.async {
            self.entrustReceive(timeout: timeout, completion: completion)
        };
    }
    
    /// 取消接收
    /// - Returns: Void
    public func asyncCancelReceive() -> Void {
        self.socketQueue.async {
            self.cancelReceive();
        }
    }
    
    public func asyncClose() ->Void {
        self.socketQueue.async {
            self.close()
        }
    }
    
}

//MARK: SocketQueue Support
extension EZSocket {
    private static let shareBufferKey = DispatchSpecificKey<UnsafeMutableRawBufferPointer>.init();
    private static let shareBufferDataKey = DispatchSpecificKey<Data>.init();

    public func sharedBuffer() -> UnsafeMutableRawBufferPointer {
        return Self.sharedBuffer(self.socketQueue)
    }
    
    public static func sharedBuffer(_ queue: DispatchQueue) -> UnsafeMutableRawBufferPointer {
        var buffer : UnsafeMutableRawBufferPointer? = queue.getSpecific(key: EZSocket.shareBufferKey)
        if buffer == nil {
            let count = 65535
            let buf = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: 0)
            buffer = UnsafeMutableRawBufferPointer(start: buf, count: count)
            let data: Data = Data(bytesNoCopy: buf, count: count, deallocator: .custom({ _,_ in
                buf.deallocate()
            }))
            queue.setSpecific(key: EZSocket.shareBufferDataKey, value: data)
            queue.setSpecific(key: EZSocket.shareBufferKey, value: buffer);
        }
        return buffer!
    }

    /// 默认socket线程，需要的话，可以扩充成线程池
    public private(set) static var sharedSocketQueue : DispatchQueue = DispatchQueue.init(label: "ITSocket.sharedSocketQueue", qos: .userInteractive);
}
